/*
 * lista.c
 *
 *  Created on: 28/03/2013
 *      Author: dario
 */

#include "lista.h"

Lista* ConstruirLista(void (*Funcion)(void* a)) {
	Lista* list = (Lista*) malloc(sizeof(Lista));
	list->length = 0;
	list->primero = NULL;
	list->actual = NULL;
	list->ultimo = NULL;
	list->DestructorDelDato = Funcion;
	return list;
}

void DestruirLista(Lista* list) {
	int i;
	Nodo* n = list->primero;
	Nodo* siguiente;
	for (i = 0; i < list->length; i++) {
		siguiente = GetNodoEnlazado(n);
		DestruirNodo(n);
		n = siguiente;
	}
	free(list);
}

int ListaVacia(Lista* list) {
	return (list->length == 0);
}

/*Es diferente agregar un elemetno si la lista esta vacia, si tiene un elemento
 *o mas de uno.
 */
int AgregarElemento(Lista* list, void* elemento) {
	Nodo* n = ConstruirNodo(elemento, NULL, list->DestructorDelDato);

	if (ListaVacia(list)) {
		list->primero = n;
	} else {
		if (list->length == 1) {
			SetNodoEnlazado(list->primero, n);
		}

		else {
			SetNodoEnlazado(list->ultimo, n);
		}
	}
	list->ultimo = n;
	list->length++;
	return GetLongitud(list);
}

int GetLongitud(Lista* list) {
	return list->length;
}

int IniciarRecorrido(Lista* list) {
	if (ListaVacia(list))
		return ERROR_LISTA_VACIA;
	else {
		list->actual = list->primero;
	}
	return RES_OK;
}

void* GetElementoActual(Lista* list) {
	if (list->actual) {
		/*Se obtiene el elemento del nodo*/
		void* elemento = GetElementoNodo((list->actual));
		/*Se avanza el nodo actual al siguiente*/
		list->actual = GetNodoEnlazado(list->actual);
		return elemento;
	} else
		return NULL;

}

void* ExisteElemento(Lista* list, void* elemento,
		int (*pfuncion)(void* a, void* b)) {
	if (IniciarRecorrido(list) != ERROR_LISTA_VACIA) {
		int encontrado = 0;
		int fin_lista = 0;
		void* actual;
		while ((!encontrado) && (!fin_lista)) {
			actual = GetElementoActual(list);
			if (!actual) {
				fin_lista = 1;
			} else {

				encontrado = (pfuncion(actual, elemento));
			}
		}
		if (encontrado)
			return actual;
		else
			return 0;
	} else
		return 0;
}

void* GetPrimerElemento(Lista* list) {
	return GetElementoNodo(list->primero);
}

void DestructuraDeListas(void* l) {
	DestruirLista((Lista*) l);
}

void ImprimirLista(Lista* l, void (*Impresora)(void* a)) {
	IniciarRecorrido(l);
	void* elemento_actual = GetElementoActual(l);
	while (elemento_actual) {
		Impresora(elemento_actual);
		elemento_actual = GetElementoActual(l);
	}
}

int DevolverIndiceElemento(Lista* list, void* elemento,
		int (*Comparadora)(void* a, void* b)) {
	if (IniciarRecorrido(list) != ERROR_LISTA_VACIA) {
		int encontrado = 0;
		int fin_lista = 0;
		int posicion = -1;
		void* actual;
		while ((!encontrado) && (!fin_lista)) {
			actual = GetElementoActual(list);
			if (!actual) {
				fin_lista = 1;
			} else {

				encontrado = (Comparadora(actual, elemento));
				posicion++;
			}
		}
		if (encontrado)
			return posicion;
		else
			return -1;
	} else
		return -1;
}

void* GetElementoXIndice(Lista* list, int indice) {
	if (indice >= list->length)
		return NULL;
	else {
		IniciarRecorrido(list);
		void* actual=NULL;
		int i;
		for (i = 0; i < indice + 1; i++) {
			actual = GetElementoActual(list);
		}
		return actual;
	}
}

